package com.zhangdi.demo.jdbc.tree;


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class TreeUtil {
    private static String IS_CHILD = "child";
    private static String NODE_ID_METHOD_NAME = "getId";
    private static String PARENT_METHOD_NAME = "getPid";
    private static String CHILDREN_METHOD_NAME = "getChildren";
    private static String ALL_CHILDREN_METHOD_NAME = "getAllChildren";

    public static <K, V> Map<K, V> list2Map(List<V> list, String keyMethodName, Class<V> c) {
        Map<K, V> map = new HashMap<K, V>();
        if (list != null) {
            try {
                Method methodGetKey = c.getMethod(keyMethodName);
                for (int i = 0; i < list.size(); i++) {
                    V value = list.get(i);
                    K key = (K) methodGetKey.invoke(list.get(i));
                    map.put(key, value);
                }
            } catch (Exception e) {
                throw new IllegalArgumentException("找不到指定的属性");
            }
        }

        return map;
    }

    public static <K, V> List<V> list2tree(List<V> result, Class<V> c) {
        Map<K, V> treeNodesMap = list2Map(result, NODE_ID_METHOD_NAME, c);

        V treeNode = null;
        V parentTreeNode = null;
        Iterator<V> iter = treeNodesMap.values().iterator();
        while (iter.hasNext()) {
            treeNode = iter.next();
            long parentId = 0;
            try {
                    parentId = (Long) treeNode.getClass().getMethod(PARENT_METHOD_NAME).invoke(treeNode);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }

            if (!treeNodesMap.containsKey(parentId)) {
                continue;
            }

            parentTreeNode = treeNodesMap.get(parentId);
            try {
                treeNode.getClass().getField(IS_CHILD).setBoolean(treeNode, true);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException ee){
                ee.printStackTrace();
            }

            List<V> children = null;
            try {
                    children = (ArrayList<V>) parentTreeNode.getClass().getMethod(CHILDREN_METHOD_NAME).invoke(parentTreeNode);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            children.add(treeNode);
        }

        List<V> treeNodesList = new ArrayList<V>();
        if (treeNodesMap.size() == 0) {
            return treeNodesList;
        }

        V node = null;
        Iterator<V> treesIter = treeNodesMap.values().iterator();
        while (treesIter.hasNext()) {
            node = treesIter.next();
            boolean isChild = false;
            try {
                    isChild = node.getClass().getField(IS_CHILD).getBoolean(node);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            if (!isChild) {
                treeNodesList.add(node);
                try {
                    treeNodesList.addAll((ArrayList<V>) node.getClass().getMethod(ALL_CHILDREN_METHOD_NAME).invoke(node));
                } catch (IllegalAccessException  e) {
                    e.printStackTrace();
                }catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
        }

        for (int i = treeNodesList.size() - 1; i >= 0; --i) {
            boolean isChild = false;
            try {
                isChild = treeNodesList.get(i).getClass().getField(IS_CHILD).getBoolean(treeNodesList.get(i));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            if (isChild) {
                treeNodesList.remove(i);
            }
        }

        return treeNodesList;
    }

    public static <K, V> List<V> list2tree(List<V> result, Class<V> c, String keyMethodName) {
        Map<K, V> treeNodesMap = list2Map(result, keyMethodName, c);

        V treeNode = null;
        V parentTreeNode = null;
        Iterator<V> iter = treeNodesMap.values().iterator();
        while (iter.hasNext()) {
            treeNode = iter.next();
            long parentId = 0;
            try {
                parentId = (Long) treeNode.getClass().getMethod(PARENT_METHOD_NAME).invoke(treeNode);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }

            if (!treeNodesMap.containsKey(parentId)) {
                continue;
            }

            parentTreeNode = treeNodesMap.get(parentId);
            try {
                Field isChildField = null;
                isChildField = treeNode.getClass().getDeclaredField(IS_CHILD);
                if (isChildField == null) {
                    isChildField = treeNode.getClass().getField(IS_CHILD);
                }
                isChildField.setBoolean(treeNode, true);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (NoSuchFieldException e) {
                e.printStackTrace();
            }

            List<V> children = null;
            try {
                children = (ArrayList<V>) parentTreeNode.getClass().getMethod(CHILDREN_METHOD_NAME).invoke(parentTreeNode);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            children.add(treeNode);
        }

        List<V> treeNodesList = new ArrayList<V>();
        if (treeNodesMap.size() == 0) {
            return treeNodesList;
        }

        V node = null;
        Iterator<V> treesIter = treeNodesMap.values().iterator();
        while (treesIter.hasNext()) {
            node = treesIter.next();
            boolean isChild = false;
            try {
                isChild = node.getClass().getField(IS_CHILD).getBoolean(node);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e){
                e.printStackTrace();
            }
            if (!isChild) {
                treeNodesList.add(node);
                try {
                    treeNodesList.addAll((ArrayList<V>) node.getClass().getMethod(ALL_CHILDREN_METHOD_NAME).invoke(node));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
        }

        for (int i = treeNodesList.size() - 1; i >= 0; --i) {
            boolean isChild = false;
            try {
                isChild = treeNodesList.get(i).getClass().getField(IS_CHILD).getBoolean(treeNodesList.get(i));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            if (isChild) {
                treeNodesList.remove(i);
            }
        }

        return treeNodesList;
    }

    public static <K, V> List<V> list2treeSort(List<V> result, Class<V> c) {
        Map<K, V> treeNodesMap = list2Map(result, NODE_ID_METHOD_NAME, c);

        V treeNode = null;
        V parentTreeNode = null;
        Iterator<V> iter = treeNodesMap.values().iterator();
        while (iter.hasNext()) {
            treeNode = iter.next();
            long parentId = 0;
            try {
                parentId = (Long) treeNode.getClass().getMethod(PARENT_METHOD_NAME).invoke(treeNode);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e){
                e.printStackTrace();
            }catch (InvocationTargetException e){
                e.printStackTrace();
            }

            if (!treeNodesMap.containsKey(parentId)) {
                continue;
            }

            parentTreeNode = treeNodesMap.get(parentId);
            try {
                treeNode.getClass().getField(IS_CHILD).setBoolean(treeNode, true);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e){
                e.printStackTrace();
            }

            List<V> children = null;
            try {
                children = (ArrayList<V>) parentTreeNode.getClass().getMethod(CHILDREN_METHOD_NAME).invoke(parentTreeNode);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e){
                e.printStackTrace();
            }catch (InvocationTargetException e){
                e.printStackTrace();
            }
            children.add(treeNode);
        }

        List<V> treeNodesList = new ArrayList<V>();
        if (treeNodesMap.size() == 0) {
            return treeNodesList;
        }

        V node = null;
        Iterator<V> treesIter = treeNodesMap.values().iterator();
        while (treesIter.hasNext()) {
            node = treesIter.next();
            boolean isChild = false;
            try {
                isChild = node.getClass().getField(IS_CHILD).getBoolean(node);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (NoSuchFieldException e){
                e.printStackTrace();
            }
            if (!isChild) {
                treeNodesList.add(node);
                try {
                    treeNodesList.addAll((ArrayList<V>) node.getClass().getMethod(ALL_CHILDREN_METHOD_NAME).invoke(node));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e){
                    e.printStackTrace();
                }catch (InvocationTargetException e){
                    e.printStackTrace();
                }
            }
        }

        for (int i = treeNodesList.size() - 1; i >= 0; --i) {
            boolean isChild = false;
            try {
                isChild = treeNodesList.get(i).getClass().getField(IS_CHILD).getBoolean(treeNodesList.get(i));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }catch (NoSuchFieldException e){
                e.printStackTrace();
            }
            if (isChild) {
                treeNodesList.remove(i);
            }
        }

//        Collections.sort(treeNodesList, comparator);

//        for (V v : treeNodesList) {
//            List<V> children = null;
//            try {
//                children = (ArrayList<V>) v.getClass().getMethod(CHILDREN_METHOD_NAME).invoke(v);
//            } catch (IllegalAccessException e) {
//                e.printStackTrace();
//            } catch (NoSuchMethodException e){
//                e.printStackTrace();
//            }catch (InvocationTargetException e){
//                e.printStackTrace();
//            }
//
//            if (children == null || children.size() == 0) {
//                continue;
//            }
//
//            Collections.sort(children, comparator);
//        }

        return treeNodesList;
    }

    private static Comparator comparator = new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            int v1 = 0;
            int v2 = 0;
            try {
                v1 = (Integer) o1.getClass().getMethod("getSort").invoke(o1);
                v2 = (Integer) o2.getClass().getMethod("getSort").invoke(o2);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e){
                e.printStackTrace();
            }catch (InvocationTargetException e){
                e.printStackTrace();
            }
            return v1 - v2;
        }
    };
}
